#pragma once
#include "Log.hpp"
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;
class Sock
{
    static const int defaultfd = -1;
    static const int n = 32;

public:
    Sock() : _listenfd(defaultfd)
    {
    }
    ~Sock()
    {
        if (_listenfd != defaultfd)
            close(_listenfd);
    }
    void Socket()
    {
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd == -1)
        {
            logMessage(ERROR, "sock fail : %s", strerror(errno));
            exit(SOCK_ERR);
        }
        logMessage(NORMAL, "sock success");
        int opt = 1;
        setsockopt(_listenfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
    }
    void Bind(const uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(port);
        int ret = bind(_listenfd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret == -1)
        {
            logMessage(ERROR, "bind fail : %s", strerror(errno));
            exit(BIND_ERR);
        }
        logMessage(NORMAL, "bind success");
    }
    void Listen()
    {
        if (listen(_listenfd, n) < 0)
        {
            logMessage(ERROR, "listen fail : %s", strerror(errno));
            exit(LISTEN_ERR);
        }
        logMessage(NORMAL, "listen success");
    }
    int Accept(int &err)
    {
        struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        int ret = accept(_listenfd, (struct sockaddr *)&addr, &len);
        err = errno;
        if (ret == -1)
            return -1;
        string ip = inet_ntoa(addr.sin_addr);
        uint16_t port = ntohs(addr.sin_port);
        logMessage(NORMAL, "accept success : [%d][%s][%d]", ret, ip.c_str(), port);
        return ret;
    }
    int getFd()
    {
        return _listenfd;
    }

private:
    int _listenfd;
};